/*
 * Copyright (C) 2008 Universidade Federal de Campina Grande
 *  
 * This file is part of OurGrid. 
 *
 * OurGrid is free software: you can redistribute it and/or modify it under the
 * terms of the GNU Lesser General Public License as published by the Free 
 * Software Foundation, either version 3 of the License, or (at your option) 
 * any later version. 
 * 
 * This program is distributed in the hope that it will be useful, but WITHOUT 
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
 * for more details. 
 * 
 * You should have received a copy of the GNU Lesser General Public License 
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 * 
 */
package org.ourgrid.aggregator.controller;

import static org.ourgrid.common.interfaces.Constants.LINE_SEPARATOR;

import org.ourgrid.aggregator.AggregatorConfiguration;
import org.ourgrid.aggregator.AggregatorConstants;
import org.ourgrid.aggregator.controller.actions.ds.GetPeerStatusProviderRepeatedAction;
import org.ourgrid.aggregator.controller.messages.AggregatorControlMessages;
import org.ourgrid.aggregator.dao.AggregatorDAO;
import org.ourgrid.aggregator.status.AggregatorCompleteStatus;
import org.ourgrid.common.config.Configuration;
import org.ourgrid.common.interfaces.CommunityStatusProvider;
import org.ourgrid.common.interfaces.RemoteWorkerProvider;
import org.ourgrid.common.interfaces.management.AggregatorManager;
import org.ourgrid.common.interfaces.status.AggregatorStatusProviderClient;
import org.ourgrid.common.interfaces.status.PeerStatusProvider;
import org.ourgrid.common.statistics.util.hibernate.HibernateUtil;
import org.ourgrid.discoveryservice.DiscoveryServiceConstants;

import br.edu.ufcg.lsd.commune.Module;
import br.edu.ufcg.lsd.commune.ModuleProperties;
import br.edu.ufcg.lsd.commune.api.FailureNotification;
import br.edu.ufcg.lsd.commune.api.MonitoredBy;
import br.edu.ufcg.lsd.commune.api.RecoveryNotification;
import br.edu.ufcg.lsd.commune.container.control.ModuleControlClient;
import br.edu.ufcg.lsd.commune.container.control.ServerModuleController;
import br.edu.ufcg.lsd.commune.context.ModuleContext;
import br.edu.ufcg.lsd.commune.identification.ContainerID;
import br.edu.ufcg.lsd.commune.identification.ServiceID;

/**
 * @author alan
 *
 */
public class AggregatorComponentController extends ServerModuleController 
	implements AggregatorManager {

	private static final String DEF_CONF_XML_PATH = "aggregator-hibernate.cfg.xml";
	
	private final String hibCfgPath;
	
	public AggregatorComponentController(String hibCfgPath) {
		this.hibCfgPath = hibCfgPath;
	}
	public AggregatorComponentController() {
		this(DEF_CONF_XML_PATH);
	}
	

	/* (non-Javadoc)
	 * @see br.edu.ufcg.lsd.commune.container.control.ApplicationServerController#getComponentName()
	 */
	@Override
	public String getComponentName() {
		return "Aggregator";
	}


	/* (non-Javadoc)
	 * @see br.edu.ufcg.lsd.commune.container.control.ApplicationServerController#createDAOs()
	 */
	@Override
	protected void createDAOs() {
		getServiceManager().createDAO(AggregatorDAO.class);
	}
	
	/* (non-Javadoc)
	 * @see br.edu.ufcg.lsd.commune.container.control.ApplicationServerController#createServices()
	 */
	@Override
	protected void createServices() {
		getServiceManager().deploy(AggregatorConstants.OBJECT_NAME, new AggregatorController());
	}

	/* (non-Javadoc)
	 * @see br.edu.ufcg.lsd.commune.container.control.ApplicationServerController#createMonitors()
	 */
	@Override
	protected void createMonitors() {
		
		getServiceManager().deploy(AggregatorConstants.DS_MONITOR_OBJECT_NAME, 
				new CommunityStatusProviderNotificationController());
	}
	
	/* (non-Javadoc)
	 * @see br.edu.ufcg.lsd.commune.container.control.ApplicationServerController#startComponent()
	 */
	@Override
	protected void startComponent() throws Exception {
	
		HibernateUtil.setUp(hibCfgPath);
		
		ServiceID serviceID = new ServiceID(
				new ContainerID(
						getServiceManager().getContainerContext().getProperty(AggregatorConfiguration.PROP_DS_USERNAME),
						getServiceManager().getContainerContext().getProperty(AggregatorConfiguration.PROP_DS_SERVERNAME),
						DiscoveryServiceConstants.MODULE_NAME),
				DiscoveryServiceConstants.COMMUNITY_STATUS_PROVIDER);
		
		getServiceManager().registerInterest(AggregatorConstants.DS_MONITOR_OBJECT_NAME, 
				serviceID.toString(), 
				CommunityStatusProvider.class);
		
		getServiceManager().addActionForRepetition(
				AggregatorConstants.GET_PEER_STATUS_PROVIDER_ACTION_NAME, 
				new GetPeerStatusProviderRepeatedAction());
		
		getServiceManager().getLog().info(AggregatorControlMessages.getSuccessfullyStartedAggregatorMessage());
	}


	public void getCompleteStatus(@MonitoredBy(Module.CONTROL_OBJECT_NAME) 
			AggregatorStatusProviderClient client) {
		if (canStatusBeUsed()) {
			AggregatorCompleteStatus completeStatus = getCompleteStatus();
			client.hereIsCompleteStatus( completeStatus );
		}
	}
	
	private AggregatorCompleteStatus getCompleteStatus() {
		return new AggregatorCompleteStatus( 
				getDiscoveryServiceID(),
				getServiceManager().getContainerDAO().getUpTime(),
				getDescription(getServiceManager().getContainerContext()) );
	}

	private ServiceID getDiscoveryServiceID() {
		AggregatorDAO aggDao = getServiceManager().getDAO(AggregatorDAO.class);
		return getServiceManager().getStubDeploymentID(
				aggDao.getCommunityStatusProvider()).getServiceID();
	}


	public void aggregatorStatusProviderClientIsUp(
			AggregatorStatusProviderClient statusProviderClient) { }
	
	public void aggregatorStatusProviderClientIsDown(
			AggregatorStatusProviderClient statusProviderClient) { }
	
	
	@RecoveryNotification
	public void remoteWorkerProviderIsUp(RemoteWorkerProvider rwp) {
		
	}
	
	@FailureNotification
	public void remoteWorkerProviderIsDown(RemoteWorkerProvider rwp) {
		
	}
	
	@RecoveryNotification
	public void peerStatusProviderIsUp(PeerStatusProvider provider) {
		
	}
	
	@FailureNotification
	public void peerStatusProviderIsDown(PeerStatusProvider provider) {
		
	}
	
	private String getDescription(ModuleContext containerContext) {
		
		StringBuilder conf = new StringBuilder();

		conf.append( "\tVersion: " ).append( Configuration.VERSION ).append( LINE_SEPARATOR );

		conf.append( "\tConfiguration directory: " );
		conf.append( containerContext.getProperty(ModuleProperties.PROP_CONFDIR) );
		conf.append( LINE_SEPARATOR );
		
		conf.append( containerContext.toString() );

		return conf.toString();
	}
	
	@Override
	protected boolean validateStartSenderPublicKey(ModuleControlClient client, String senderPublicKey) {
		
		if(!getServiceManager().isThisMyPublicKey(senderPublicKey)) {
			getServiceManager().getLog().warn(AggregatorControlMessages.getUnknownSenderStartingAggregatorMessage(senderPublicKey));
			return false;
		}
		return true;
	}

	@Override
	protected boolean validateStopSenderPublicKey(ModuleControlClient client, String senderPublicKey) {
		
		if(!getServiceManager().isThisMyPublicKey(senderPublicKey)) {
			getServiceManager().getLog().warn(AggregatorControlMessages.getUnknownSenderStoppingAggregatorMessage(senderPublicKey));
			return false;
		}
		return true;
	}

}
